package org.zhaya.sdk.processors;

import io.logz.sawmill.*;
import io.logz.sawmill.annotations.ProcessorProvider;
import io.logz.sawmill.exceptions.ProcessorConfigurationException;
import io.logz.sawmill.utilities.JsonUtils;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.inject.Inject;
import java.util.Map;
import java.util.Objects;

/**
 * @author zhaotrent
 */
@ProcessorProvider(
        type = "translate",
        factory = TranslateProcessor.Factory.class
)
public class TranslateProcessor implements Processor {
    private final String field;
    private final String targetField;
    private final Map<String, String> dictionary;
    private final Template fallback;

    public TranslateProcessor(String field, String targetField, Map<String, String> dictionary, Template fallback) {
        this.field = Objects.requireNonNull(field, "field cannot be null");
        this.targetField = Objects.requireNonNull(targetField, "targetField cannot be null");
        this.dictionary = Objects.requireNonNull(dictionary, "dictionary cannot be null");
        this.fallback = fallback;
    }

    @Override
    public ProcessResult process(Doc doc) {
        if (!doc.hasField(this.field, String.class)) {
            return ProcessResult.failure(String.format("failed to translate field in path [%s], field is missing or not instance of String", this.field));
        } else {
            String value = doc.getField(this.field);
            String translation = this.dictionary.get(value);

            if (translation == null) {
                if (this.fallback != null) {
                    doc.addField(this.targetField, this.fallback.render(doc));
                }
            } else {
                doc.addField(this.targetField, translation);
            }

            return ProcessResult.success();
        }
    }

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Configuration implements Processor.Configuration {
        private String field;
        private String targetField = "translation";
        private Map<String, String> dictionary;
        private String fallback;
    }

    public static class Factory implements Processor.Factory {
        private final TemplateService templateService;

        @Inject
        public Factory(TemplateService templateService) {
            this.templateService = templateService;
        }

        @Override
        public TranslateProcessor create(Map<String, Object> config) {
            Configuration translateConfig = JsonUtils.fromJsonMap(Configuration.class, config);
            String field = translateConfig.getField();
            Map<String, String> dictionary = translateConfig.getDictionary();
            if (field != null && dictionary != null) {
                Template fallback = translateConfig.getFallback() != null ? this.templateService.createTemplate(translateConfig.getFallback()) : null;
                return new TranslateProcessor(field, translateConfig.getTargetField(), dictionary, fallback);
            } else {
                throw new ProcessorConfigurationException("field and dictionary cannot be null");
            }
        }
    }
}

